package ink.feny.security.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import ink.feny.security.service.JwtService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录验证
 * @author Feny
 * @date Created in 2021/4/28
 */
@Slf4j
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
    @Autowired
    private JwtService jwtService;

    private RequestCache requestCache = new HttpSessionRequestCache();

    public LoginFilter(AuthenticationManager authenticationManager) {
        // 修改默认传参名
        // setUsernameParameter("phone");
        // setPasswordParameter();
        setAuthenticationManager(authenticationManager);
        super.setFilterProcessesUrl("/auth/login");
    }

    /**
     * 覆盖为JSON方式
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @return org.springframework.security.core.Authentication
     * @author Feny
     * @date 2021/4/28
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            // 表单登录
            if (!isJsonRequest(request)) {
                String username = request.getParameter(getUsernameParameter());
                String password = request.getParameter(getPasswordParameter());

                return getAuthenticationManager().authenticate(
                        new UsernamePasswordAuthenticationToken(
                                username,
                                SecureUtil.md5(password),
                                new ArrayList<>())
                );
            }

            Map map = new ObjectMapper().readValue(request.getInputStream(), Map.class);
            return getAuthenticationManager().authenticate(
                    new UsernamePasswordAuthenticationToken(
                            map.get("username"),
                            SecureUtil.md5((String) map.get("password")),
                            new ArrayList<>())
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("token", jwtService.generateToken(authResult.getName()));
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().write(JSONUtil.toJsonPrettyStr(result));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.error("错误信息：{}", failed.getMessage(), failed);

        Map<String, Object> result = new HashMap<>();
        result.put("msg", "用户名或密码不正确");
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        response.getWriter().write(JSONUtil.toJsonPrettyStr(result));
    }

    private boolean isJsonRequest(HttpServletRequest request) {
        String accept = request.getHeader("Content-Type");
        return StrUtil.contains(accept, MediaType.APPLICATION_JSON_VALUE);
    }
}
